﻿
using Boilen.Primitives.Members;
using System.Collections.Generic;
using System.ComponentModel;


namespace Boilen.Primitives.Implementers {

    /// <inheritdoc/>
    /// <summary>
    /// Implements an immutable property.
    /// </summary>
    public sealed class ImmutableProperty<T> : Property<T> {

        internal const string DescriptionFormat = "Gets {0}.";


        /// <summary>
        /// Gets or sets a value indicating whether to include a constructor initializer for the property, or to rely on the default value.
        /// </summary>
        public bool IncludeInConstructor { get; set; }

        /// <inheritdoc/>
        public override string FieldModifiers {
            get { return base.FieldModifiers + " readonly"; }
        }

        /// <inheritdoc/>
        protected override IEnumerable<InitializationMember> Initializers {
            get {
                // Parameter initalizer.
                if( this.IncludeInConstructor )
                    yield return new InitializationMember( this.FieldName, this.FieldTypeName, this.Name ) {
                        Doc = this.CreateDoc( ).AddParam( this.Name, this.Description == null ? null : Util.Capitalize( this.Description ) + "." )
                    }.AddGuards( this.Guards );

                // Default value initializer.
                foreach( var condition in this.DefaultValues.Keys ) {
                    string defaultValue = this.DefaultValues[condition];
                    yield return new InitializationMember( this.FieldName, defaultValue ) { Condition = condition };
                }
            }
        }

        /// <inheritdoc/>
        protected override AccessorMember Accessor {
            get {
                return new AccessorMember( this.AccessorName, this.TypeName ) {
                    Doc = this.CreateDoc( )
                        .AddSummary( DescriptionFormat, this.Description ),
                    Modifiers = this.AccessorModifiers,
                    ObserveMember = this.CreateAccessorBlock(
                        ObserveAccessorName,
                        string.Format( "return this.{0};", this.FieldName )
                    )
                };
            }
        }


        /// <inheritdoc/>
        public ImmutableProperty( PartialType parent, string name, string description )
            : base( parent, name, description ) {
            this.IncludeInConstructor = true;
        }


        /// <summary>
        /// Assigns the value used for the <see cref="IncludeInConstructor"/> property.
        /// </summary>
        [DefaultValue( "True" )]
        public ImmutableProperty<T> SetIncludeInConstructor( bool includeInConstructor ) {
            this.IncludeInConstructor = includeInConstructor;
            return this;
        }

    }

}
